package be.sc.classicnetwork.aspect;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.web.context.ServletContextAware;

import be.sc.classicnetwork.annotation.RefreshCache;
import be.sc.classicnetwork.model.Location;
import be.sc.classicnetwork.model.Make;
import be.sc.classicnetwork.model.Option;
import be.sc.classicnetwork.model.Site;
import be.sc.classicnetwork.model.Type;
import be.sc.classicnetwork.service.ServiceLocator;
import be.sc.classicnetwork.util.RequestAttributeConstant;

/**
 * RefreshCacheAspect.
 */
@Aspect
@SuppressWarnings("unchecked")
public class RefreshCacheAspect implements ServletContextAware {

    private ServiceLocator serviceLocator;

    private ServletContext servletContext;

    private static final Log log = LogFactory.getLog(RefreshCacheAspect.class);

    private Map allCarsCache;

    private Map allPublishedCarsCache;

    private Collection allContactsCache;

    private Map allCodesCache;

    /**
     * Method called at the initialization of the Spring context to load all the
     * cache regions.
     */
    public void init() {
	refreshCache(null);
    }

    /**
     * flushCache.
     */
    @AfterReturning("@annotation(refreshCache)")
    public void refreshCache(RefreshCache refreshCache) {
	HashMap cache = new HashMap();

	// get cache region to refresh from the annotation
	int cacheRegion = (refreshCache != null) ? refreshCache.cacheRegion() : RefreshCache.ALL;
	log.debug("Refreshing cache region " + cacheRegionToString(cacheRegion));

	switch (cacheRegion) {
	case RefreshCache.CARS:
	    refreshAllCarsCache();
	    refreshAllPublishedCarsCache();
	    break;
	case RefreshCache.CONTACTS:
	    refreshAllContactsCache();
	    break;
	case RefreshCache.ALL:
	    refreshAllCodesCache();
	    refreshAllCarsCache();
	    refreshAllPublishedCarsCache();
	    refreshAllContactsCache();
	    break;
	}

	cache.put(RequestAttributeConstant.ALL_CARS, this.allCarsCache);
	cache.put(RequestAttributeConstant.FILTERED_CARS, this.allPublishedCarsCache);
	cache.put(RequestAttributeConstant.CONTACT_LIST, this.allContactsCache);
	cache.put(RequestAttributeConstant.CODES, this.allCodesCache);

	servletContext.setAttribute(RequestAttributeConstant.CACHE, cache);
    }

    /**
     * getCodeCache.
     */
    private void refreshAllCodesCache() {
	this.allCodesCache = new HashMap();
	this.allCodesCache.put(RequestAttributeConstant.OPTION_LIST, this.serviceLocator.getCodeService().findAll(
		Option.class));
	this.allCodesCache.put(RequestAttributeConstant.TYPE_LIST, this.serviceLocator.getCodeService().findAll(
		Type.class));
	this.allCodesCache.put(RequestAttributeConstant.SITE_LIST, this.serviceLocator.getCodeService().findAll(
		Site.class));
	this.allCodesCache.put(RequestAttributeConstant.LOCATION_LIST, this.serviceLocator.getCodeService().findAll(
		Location.class));
	this.allCodesCache.put(RequestAttributeConstant.MAKE_LIST, this.serviceLocator.getCodeService().findAll(
		Make.class));
    }

    /**
     * getContactsCache.
     */
    private void refreshAllContactsCache() {
	this.allContactsCache = this.serviceLocator.getContactService().findAll(0, 0);
    }

    /**
     * getAllCars.
     */
    private void refreshAllCarsCache() {
	this.allCarsCache = new HashMap();
	this.allCarsCache.put(RequestAttributeConstant.CAR_COUNT, this.serviceLocator.getCarService().findAll(0, 1,
		false).getCount());
	this.allCarsCache.put(RequestAttributeConstant.MAKE_COUNT, this.serviceLocator.getCarService()
		.countMakes(false));
    }

    /**
     * getAllPublishedCars.
     */
    private void refreshAllPublishedCarsCache() {
	this.allPublishedCarsCache = new HashMap();
	this.allPublishedCarsCache.put(RequestAttributeConstant.CAR_COUNT, this.serviceLocator.getCarService().findAll(
		0, 1, true).getCount());
	this.allPublishedCarsCache.put(RequestAttributeConstant.MAKE_COUNT, this.serviceLocator.getCarService()
		.countMakes(true));
    }

    /**
     * getCacheRegionString.
     */
    private String cacheRegionToString(int cacheRegion) {
	switch (cacheRegion) {
	case RefreshCache.ALL:
	    return "all";
	case RefreshCache.CARS:
	    return "cars";
	case RefreshCache.CONTACTS:
	    return "contacts";
	default:
	    return "unknown";
	}
    }

    public ServiceLocator getServiceLocator() {
	return serviceLocator;
    }

    public void setServiceLocator(ServiceLocator serviceLocator) {
	this.serviceLocator = serviceLocator;
    }

    public void setServletContext(ServletContext servletContext) {
	this.servletContext = servletContext;
    }
}
